home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / uutty / part01 next >
Encoding:
Internet Message Format  |  1987-02-18  |  55.9 KB

  1. Subject:  v08i072:  Bidirectional getty/login for SystemV, Part01/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: cdx39!jc@EDDIE.MIT.EDU (John Chambers)
  6. Mod.sources: Volume 8, Issue 72
  7. Archive-name: uutty/Part01
  8.  
  9. [  I have not tried this.  --r$  ]
  10.  
  11. Hello.  Enclosed is a program which I've been using for some
  12. time as a replacement for getty; I call it "uutty" as a hint
  13. that it cooperates with uucp/uux/mail/cu/etc.  Several friends
  14. have suggested I broadcast it, so here it is....
  15.  
  16. Uutty's primary function is to make it easy to use a port in
  17. both directions with little grief.  On a port with an ACU-type
  18. modem, it allows both outgoing and incoming calls without any
  19. need to fiddle with inittab.  On a direct link, it allows the
  20. use of commands like uucp or cu in either direction at any
  21. time. 
  22.  
  23. Uutty's secondary function is to try to recognize input from 
  24. overly-intelligent modems or other login daemons, and avoid
  25. getting into a cycle-eating conversation with them.
  26.  
  27. There is also a tertiary function:  optionally producing an
  28. audit (debug) trail of traffic on the port at times when no
  29. program (such as uucico or cu) is using it.  This is mostly
  30. useful when you have a talkative modem or LAN connection.
  31.  
  32. This version should be classified as a "beta test" version;
  33. it has been tested on only a few varieties of Unix, and it
  34. will probably have to be modified for others.  The two parts
  35. that may not be very portable are the code to put a port into
  36. raw mode (makeraw.c), and the code to log in a user (*.utmp.c).
  37.  
  38. Another major reason for wanting the source code close at 
  39. hand is that you will likely have to twiddle with the code 
  40. that handles talkative modems, in order to respond correctly
  41. to your modems' own variety of bizarreness.  An especially
  42. common problem is being overly sensitive to speed.  Many
  43. modems won't accept commands at the full line speed (1200
  44. baud or whatever); they assume that commands come from a
  45. person typing at a keyboard, and lose characters when it
  46. comes from a program in a burst.  This program writes the
  47. "init" strings byte-at-a-time, which may be slow enough,
  48. but you may have to slow these writes down even more to
  49. make the modem understand.  
  50. : This is a shar archive. Extract with sh, not csh
  51. echo file: README
  52. cat > README << '\!Funky\!Stuff\!'
  53.     The uutty package is John Chambers' very own person login
  54.     daemon, to replace such things as getty(1) and login(1).
  55.     
  56.     There are several motives for doing this.  You might have
  57.     a modem which you wish to use for both incoming and outgoing
  58.     calls.  You might have a direct ("null modem") link which
  59.     you would like to use from either end.  You might have an
  60.     overly-intelligent modem which is crashing your system by
  61.     engaging getty in a conversation.  All of these can be
  62.     handled by uutty.  
  63.     
  64.     Also, uutty will make an audit trail for you in the file
  65.     of your choice.  Note:  at debug level -d2 and above,
  66.     uutty is a "Trojan horse", since the audit trail will
  67.     contain unencrypted login ids and passwords.  This is
  68.     very useful on occasion; it is also an extreme security
  69.     risk.  Think carefully before you try this on a regular
  70.     basis.
  71.     
  72.     To create the program, first edit the *.h files and the
  73.     Makefile.  There isn't much that needs to be changed,
  74.     but you probably want to modify the -DSYS5 and -DCadmus
  75.     parameters to specify your variety of Unix and your 
  76.     manufacturer's name.  You might also try:
  77.         grep SYS5 *.c
  78.         grep Cadmus *.c
  79.     and check out all these pieces of code to see if they
  80.     look correct for your system.
  81.     
  82.     If you make any interesting changes to port it to your
  83.     system, you might share them with the author:
  84.         ...!cdx39!jc (John Chambers)
  85.     This will help towards producing a truly portable version
  86.     of this logger.
  87.     
  88.     When you've convinced yourself that the system dependencies
  89.     are OK, just type "make", and uutty will be compiled.  To
  90.     install it and the manual entry , type "install"; you'll 
  91.     have to be a super-user to do this.
  92.     
  93.     To run it, you need to explain to init about it.  Here 
  94.     are some typical entries from our /etc/inittab file:
  95.  
  96. t11:23 :respawn:modem /dev/tty11 -B12                # Modem for uucp.
  97. t30:234:respawn:uutty /dev/tty30 -B96 -e 2>>/user/aud/tty30    # Ordinary terminal port.
  98. t40:34:off    : uutty /dev/tty40 -B96 2>>/user/aud/tty40 -l -d2    # Direct link.
  99. t41:34:respawn: uutty /dev/tty41 -B96 2>>/user/aud/tty41 -l -d2    # Direct link.
  100. t42:34:respawn: uutty /dev/tty42 -B96 2>>/user/aud/tty42 -l -d2    # Direct link.
  101. t43:34:respawn: uutty /dev/tty43 -B96 2>>/user/aud/tty43 -l -d2    # Direct link.
  102.  
  103.     What we are doing here is using uutty on four inter-machine
  104.     direct links (null-modem or cross-over cables), on the
  105.     tty4? ports.  The tty30 port is attached to a terminal
  106.     (well, actually to our LAN); uutty is being run there
  107.     just to show that it works with the -e option.  The tty11 
  108.     port is attached to an overly-intelligent ACU-type modem.  
  109.     The 'modem' program is a shell script, which looks like:
  110.     
  111. >    :
  112. >    MODEM=tty11
  113. >    /usr/lib/uucp/modem_init $1
  114. >    cd /etc
  115. >    PATH=.:$PATH
  116. >    exec uutty /dev/$MODEM -B12 -L -d2 -i\\rqOG0\\rXXXT\\rqOG0 2>>/user/aud/$MODEM 
  117. >    :
  118. >    : We normally won't reach this:
  119. >    sleep 30
  120. >    /usr/lib/uucp/modem_init $1
  121.     
  122.     The purpose of this is to run a special script, modem_init,
  123.     to beat on the modem and try to put it into a quiescent state.
  124.     When this is done, we run uutty at 1200 baud, with locking
  125.     enabled, at debug level 2 (tracing of all input and output),
  126.     and with a bizarre-looking initialization string which turns
  127.     out to be what this particular modem requires to force it to
  128.     hang up and re-initialize itself.  The final sleep and call
  129.     on modem_init are to handle cases where init somehow can't
  130.     find uutty, or it dies instantaneously.  This may look like
  131.     overkill; it turns out to have been useful on occasion.
  132.     
  133.     Note that the audit trail grows without bound.  Once a day,
  134.     we handle it by having cron start up /etc/cleanup, a script
  135.     that moves a select list of files to a backup copy.  This
  136.     generally suffices to keep the audit trail to a reasonable
  137.     size.
  138.     
  139.     When you first run uutty, you should probably try it with
  140.     -d5 or -d8, to have it explain what it's doing.  It will
  141.     likely get into a conversation with your modem; you'll
  142.     have to figure out if there's a possible initialization
  143.     string that will prevent it.  Hint:  Try to tell your
  144.     modem not to echo anything.
  145.     
  146.     A more useful first test is to run uutty on one end of
  147.     a null-modem cable, which could be to another computer,
  148.     or to two ports on the same computer.  Use cu(1) to
  149.     connect to it, and have either getty or uutty running
  150.     on the other end.  After at most two RETURNs, you should
  151.     get a login prompt, and uutty's audit trail should show
  152.     that there is a lockfile.  When you tell cu to disconnect,
  153.     the lockfile will go away, and uutty will wake up in
  154.     half a minute or so.  If you are still logged in at 
  155.     the other end, uutty may discover this, and log you
  156.     out; on the other hand, it may not.  (It's supposed
  157.     to, if you have a Unix prompt ending with '$' or '%'.)
  158.     
  159.     Enjoy!
  160.     
  161.     John M Chambers 
  162. Phone: 617/364-2000x7304
  163. Email: ...{cthulhu,inmet,harvax,mit-eddie,mot[bos],rclex}!cdx39!{jc,news,root,usenet,uucp}
  164. Smail: Codex Corporation; Mailstop C1-30; 20 Cabot Blvd; Mansfield MA 02048-1193
  165. Telex: 922-443 CODEX A MNSF
  166. \!Funky\!Stuff\!
  167. echo file: Makefile
  168. cat > Makefile << '\!Funky\!Stuff\!'
  169. #
  170. # Makefile for uutty login daemon.  To build uutty, just type:
  171. #    make
  172. # To install uutty and the manual page, type:
  173. #    make install
  174. # It's easiest to test if you create an inittab entry like:
  175. #    t43:234:respawn:uutty /dev/tty43 -B96 -l -d8 2>>/user/aud/tty43 
  176. # where /dev/tty43 is a null-modem link to a port on the same or
  177. # another Unix machine.  It should be tested in two directions.
  178. # First, run it with no getty on the other end, and use cu from
  179. # the other end to call up uutty.  After 1 or 2 CR or LF characters,
  180. # it should log you in.  Next, start up getty or uutty on the other
  181. # end, and use cu to connect from this end.  After CR or LF, uutty
  182. # should get out of the way and let the other end log you in.  
  183. #
  184. CFL=    -DSYS5 -DCadmus -I.
  185. CC=    cc $(CFL) -c
  186. D=    uutty.8
  187. H=    *.h 
  188. L=    cc $(CFL) -o
  189. O=    args.o awrite.o checkid.o copy.o data.o dbg.o die.o exec.o \
  190.     fillutmp.o findutmp.o gestate.o getime.o help.o lastfield.o \
  191.     lockname.o lockup.o lockwait.o main.o makeraw.o makesane.o \
  192.     nextbyte.o opendev.o option.o pread.o pswd.o pwrite.o \
  193.     restdev.o resync.o sendbrk.o shprompt.o sig.o slowly.o st.o \
  194.     talk.o unlock.o  
  195. S1=    args.c awrite.c checkid.c copy.c data.c dbg.c die.c \
  196.     exec.c fillutmp.c findutmp.c gestate.c getime.c help.c 
  197. S2=    lastfield.c lockname.c lockup.c lockwait.c \
  198.     main.c makeraw.c makesane.c nextbyte.c opendev.c option.c pread.c \
  199.     pswd.c pwrite.c restdev.c resync.c sendbrk.c shprompt.c \
  200.     sig.c slowly.c st.c talk.c unlock.c  
  201. S=    $(S1) $(S2)
  202. U1=    README Makefile install uutty.8 uutty.h dbg.h $(S1)
  203. U2=    $(S2)
  204. #
  205. # How to compile most of the modules:
  206. .c.o:    $*.c $H;    $(CC) $*.c
  207. #
  208. progs:        uutty
  209. lints:        uutty.L
  210. uutty:        $O;        $L uutty $O
  211. #
  212. # Libraries:
  213. #
  214. install:    /etc/uutty /usr/man/man8/uutty.8
  215. /etc/uutty:    uutty;        Cp uutty /etc/uutty
  216. /usr/man/man8/uutty.8: uutty.8;    Cp uutty.8 /usr/man/man8/uutty.8
  217. #
  218. # Some modules that need special treatment:
  219. #
  220. dbg.o:        dbg.c dbg.h;        $(CC) dbg.c
  221. makeraw.o:    makeraw.c dbg.h;    $(CC) makeraw.c
  222. makesane.o:    makesane.c dbg.h;    $(CC) makesane.c
  223. st.o:        st.c;            cc -c st.c
  224. #
  225. # Run lint on the whole mess:
  226. #
  227. uutty.L:    $H $S;    lint $(CFL) $S >uutty.L
  228. #
  229. # Build the distribution files:
  230. #
  231. uutty.dist:    uutty.dist1 uutty.dist2
  232. uutty.dist1:    uutty.cover1 uutty.shar1;    cat uutty.cover1 uutty.shar1 >uutty.dist1
  233. uutty.dist2:    uutty.cover2 uutty.shar2;    cat uutty.cover2 uutty.shar2 >uutty.dist2
  234. #
  235. # Build the shell archives:
  236. #
  237. uutty.shar1:    $(U1);    shar $(U1) >uutty.shar1
  238. uutty.shar2:    $(U2);    shar $(U2) >uutty.shar2
  239. #
  240. \!Funky\!Stuff\!
  241. echo file: install
  242. cat > install << '\!Funky\!Stuff\!'
  243. : Script to install uutty.
  244. :
  245. echo You must be a super-user to do this...
  246. make install
  247. \!Funky\!Stuff\!
  248. echo file: uutty.8
  249. cat > uutty.8 << '\!Funky\!Stuff\!'
  250. .\" pltroff -manl $1
  251. .TH UUTTY 8
  252. .VE 5
  253. .SH NAME
  254. uutty  \-  two-ended login protocol with intelligent modem handling and uucp lockfiles
  255. .SH SYNOPSIS
  256. .B /etc/uutty
  257. device
  258. [
  259. .B \-b<speed>
  260. ] [
  261. .B \-d<level>
  262. ] [
  263. .B \-e
  264. ] [
  265. .B \-f
  266. ] [
  267. .B \-l
  268. ] [
  269. .B \-i
  270. initializer
  271. ] [
  272. 2>>audit_file
  273. ]
  274. .br
  275. file
  276. .SH DESCRIPTION
  277. .fi
  278. .B Uutty
  279. is a program that is invoked by
  280. .IR init (8).
  281. It is similar in function to getty(8) and login(1),
  282. but has some extra intelligence so that it may be run
  283. with a single modem used for both incoming and outgoing calls,
  284. or on both ends of a direct port-to-port link.
  285. .PP
  286. With
  287. .B uutty
  288. running on both ends of a line,
  289. terminal emulators like cu(1) may be used
  290. in either direction.
  291. Also, file transfer utilities like uucp(1)
  292. may be initiated from either end.
  293. .PP
  294. An important feature of
  295. .B uutty
  296. is that is recognizes the lockfiles created by uucico(8),
  297. cu(1), uux(1), and other programs.
  298. On most Unix(TM) systems,
  299. these are named "/usr/spool/uucp/LCK..<device>",
  300. where <device> is the last field of the device name.
  301. .B Uutty
  302. checks for the presence of such lockfiles before every read,
  303. and sleeps until they disappear.
  304. .PP
  305. Thus
  306. .B uutty
  307. may be left running on a port while other programs use it.
  308. When a lockfile is created by another program
  309. (such as uucico or cu),
  310. .B uutty
  311. will read at most one more chunk of input
  312. before noticing the lockfile.
  313. It will then "back off" until the other program
  314. signals that it is done with the device by
  315. unlinking the lockfile.
  316. .PP
  317. .B Uutty
  318. is normally run as a background daemon by init(1M).
  319. The entry in /etc/inittab typically looks like:
  320. .nf
  321. .in +5
  322. t42: 34:respawn: uutty /dev/tty42 -B96 -L 2>>somewhere
  323. .in -5
  324. .fi
  325. where
  326. .I somewhere
  327. is an audit file or /dev/null.
  328. .PP
  329. Initially
  330. .B uutty
  331. writes the initialization string, if one is given,
  332. then writes a "login:" prompt to the line.
  333. It then reads the response,
  334. and attempts to determine whether it is an
  335. acceptable login attempt,
  336. or whether it is from another login process
  337. (like itself or getty or login).
  338. In the former case, a password prompt is
  339. written to the device;
  340. in the latter case, the input is ignored.
  341. .PP
  342. An important difference between
  343. .B uutty
  344. and
  345. .B getty
  346. is that
  347. .B uutty
  348. echoes nothing back to the input device.
  349. This avoids uncontrolled feedback
  350. when programs are run on both ends of a line.
  351. However, with the
  352. .B \-e
  353. option, echoing is done.
  354. .PP
  355. .B Uutty
  356. does not invoke the
  357. .IR login (1)
  358. command;
  359. rather it does the entire login interview itself.
  360. .PP
  361. .I Device
  362. is the name of a serial port
  363. (normally in \f3/dev\fP) to which
  364. .B uutty
  365. is to attach itself.
  366. .B Uutty
  367. uses this string as the filename
  368. to open for reading and writing;
  369. it should be the full pathname of the device.
  370. .PP
  371. The optional argument,
  372. .B \-B
  373. .I <speed>,
  374. is a numeric line speed.
  375. Arbitrary speeds may not be recognized;
  376. typically -B300, -B1200, -B2400, -B4800, and -B9600
  377. are the only ones that work correctly.
  378. The default speed is -B9600.
  379. The final
  380. .I 00
  381. may be omitted.
  382. .PP
  383. .B Uutty
  384. sends a login prompt whenever it receives a single CR of LF character as input.
  385. It then expects a login id,
  386. which may be terminated by a new-line or carriage-return character.
  387. Either will cause
  388. .B uutty
  389. to examine the preceding characters for acceptability.
  390. The rules are:
  391. Only printable ASCII characters are accepted,
  392. and of those, most punctuation is rejected.
  393. In particular, any input containing a colon (:)
  394. is assumed to be a prompt from another login process,
  395. and causes
  396. .B uutty
  397. to become very uncommunicative.
  398. White space (blanks and tabs) are unacceptable,
  399. as are any ASCII control characters
  400. (those below hex 20).
  401. .PP
  402. Note that the initial CR or LF must be 'alone',
  403. ining that they must not be followed too soon by
  404. any other characters.
  405. If
  406. .B uutty
  407. finds junk in the input buffer after a CR or LF,
  408. the entire chunk of input is discarded.
  409. This is done to try to avoid getting into
  410. discussions with intelligent modems.
  411. .PP
  412. When acceptable input is received,
  413. a password prompt is sent,
  414. and the response (if any) is subjected to the same
  415. tests as for the login id.
  416. .PP
  417. If the login id and password agree with an entry in the
  418. password file /etc/passwd,
  419. the user's shell is initiated via execv(2),
  420. in the same process in which
  421. .B uutty
  422. was running.
  423. .PP
  424. If a ^C character (numeric 3) is received,
  425. .B uutty
  426. terminates.
  427. Also, this will usually result in the device not being open by any process,
  428. resulting in a "hangup" operation being performed by
  429. the device driver.
  430. See termio(8) for details.
  431. Normally, init(1M) will soon restart the process,
  432. and a new initialization string and login prompt will
  433. be sent to the device.
  434. .PP
  435. The
  436. .B \-i
  437. option is used to supply an initialization string
  438. to be sent when uutty determines that a connection
  439. exists to another system which should be terminated.
  440. The rest of the command-line argument should be the
  441. string, in which several types of notation may be
  442. used to produce non-printing characters.
  443. A complicated example is:
  444. .in +5
  445. .B "-i'\\\\33^T[j%7Fxx\\\\r'"
  446. .in -5
  447. The quotes are to prevent the shell from interpreting anything.
  448. The
  449. .B "\\\\33"
  450. is an octal value for an ASCII ESC character.
  451. The
  452. .B "^T"
  453. is a CTRL-T character, i.e., octal 24 or hex 14, ASCII DC4.
  454. The
  455. .B j
  456. represents itself.
  457. The
  458. .B "%7F"
  459. is a hex value for a DEL character.
  460. The
  461. .B xx
  462. represent themselves.
  463. The final
  464. .B "\\\\r"
  465. is a carriage-return character,
  466. as in the C language conventions.
  467. .PP
  468. A debug option is provided.  When
  469. .B getty
  470. is invoked with the
  471. .B \-d<n>
  472. option, various debugging messages are produced,
  473. depending on the value of the digit <n>.
  474. Such messages are always written to the "standard error" file.
  475. The default is
  476. .B \-d1 ,
  477. which produces output giving the times at which
  478. .B uutty
  479. is started, and when it initiates a shell for some user.
  480. The
  481. .B \-d0
  482. level suppresses all output except fatal error messages.
  483. Higher numbers produce successively more output.
  484. The
  485. .B \-d4
  486. level will generally give sufficient information to
  487. explain just what messages are seen by
  488. .B uutty
  489. and why logins are succeeding or failing.
  490. .PP
  491. If user logins are desired on a port used by uucp(1),
  492. it is a good idea to create lockfiles.
  493. Otherwise, a uucp demon (uucico) may attempt to use the port,
  494. and sheer insanity results.
  495. The
  496. .B \-l
  497. option causes a uucp lockfile to be created for the duration of a login,
  498. preventing uucp from attempting to use the port.
  499. On logout, the lockfile will be removed.
  500. Note:
  501. This implies that the shell is run as a subprocess to uutty,
  502. so ps(1) will show both processes running.
  503. Don't kill the uutty process;
  504. doing so will block further accesses to the port by
  505. uutty or uucp,
  506. until you delete the lockfile by hand.
  507. .PP
  508. If for some reason you wish to start shells in subprocesses,
  509. this may be done via the
  510. .B \-f
  511. option, which stands for "fork".
  512. The
  513. .B \-l
  514. option implies the
  515. .B \-f
  516. option.
  517. .SH FILES
  518. /etc/passwd
  519. /etc/utmp
  520. /usr/spool/uucp/LCK..<device> .
  521. Note: /etc/gettydefs is not referenced by
  522. .I uutty .
  523. .SH "SEE ALSO"
  524. cu(1),
  525. getty(8),
  526. init(8),
  527. inittab(5),
  528. ioctl(2),
  529. login(1),
  530. tty(7),
  531. uucico(8),
  532. uucp(1),
  533. uux(1)
  534. .SH "BUGS"
  535. Programs that don't know how to create uucp(1) lockfiles shouldn't
  536. be run on a port controlled by
  537. .B uutty .
  538. If you must, try surrounding them with a script that creates the
  539. lockfile.
  540. .PP
  541. The
  542. .B \-e
  543. option entails a high risk of feedback saturating either or both
  544. of the computers involved.
  545. .PP
  546. If a
  547. .B CR
  548. or
  549. .B LF
  550. is followed too quickly by further input,
  551. it will be silently discarded.
  552. This is frustrating to people that like to bang
  553. on the RETURN key.
  554. .PP
  555. There are all sorts of truly demented modems on the market;
  556. you may well have to twiddle with the code a bit to persuade
  557. .B uutty
  558. to ingore your modem's noise.
  559. .PP
  560. At debug levels -d2 and above,
  561. .B uutty
  562. is a Trojan Horse,
  563. writing login ids and passwords in the clear to the audit trail.
  564. \!Funky\!Stuff\!
  565. echo file: uutty.h
  566. cat > uutty.h << '\!Funky\!Stuff\!'
  567. #ifndef uutty_h
  568. #include "dbg.h"
  569. /* 
  570. ** This is the header file for John Chambers' "Serial Port Daemon".
  571. ** Several programs use this header, including "uutty", so there 
  572. ** is likely to be stuff here not needed by a particular program.
  573. ** A single header is used to make them somewhat consistent.
  574. */
  575. /*
  576. ** The following stuff may be specific to Unix SYS/V:
  577. */
  578. #ifdef   SYS5
  579. #include <pwd.h>
  580. #include <termio.h>
  581. #include <utmp.h>
  582. #include <sys/errno.h>
  583. #include <sys/stat.h>
  584.   extern struct passwd*getpwnam();
  585.   extern int           ttyslot(); 
  586.   extern struct utmp  *getutent(); 
  587.   extern struct utmp  *getutline(); 
  588.   extern void          pututline(); 
  589.   extern void          setutent(); 
  590.   extern struct stat   status;        /* Child process's status */
  591.   extern struct termio trminit;
  592.   extern int           ttyslot(); 
  593.   extern struct utmp  *up;
  594.   extern struct utmp   utmp;
  595. #endif
  596. /*
  597. ** Unix library stuff:
  598. */
  599. extern char **environ;    /* Environment vector */
  600. extern char  *crypt();    /* Password encryption */
  601. extern char  *ctime();    /* Date/time in ASCII */
  602. /*
  603. ** State-type codes, see also the state[] array.
  604. */
  605. #define S_INIT        0
  606. #define S_IDLE        1
  607. #define S_LOGIN        2
  608. #define S_PASSWD    3
  609. #define S_DL        11
  610. #define S_RX        12
  611. #define S_TC        13
  612. #define S_BV_E        14
  613. #define S_HSUQ        15
  614. #define S_HSU        16
  615. #define S_READS        17
  616. #define S_GO        18
  617. #define S_TRANS        19
  618. #define S_CTRLA        20
  619. #define S_CTRLB        21
  620. #define S_CTRLC        22
  621. #define S_CTRLD        22
  622. #define S_CONNECT    33
  623. #define S_ID        34
  624. #define S_SREC        36
  625. #define S_SR        37
  626. #define S_EXIT        38
  627. #define S_LOAD        39
  628. /*
  629. ** Array sizes.
  630. */
  631. #define BUF    80        /* Size of scratch buffer */
  632. #define IBUF 1000        /* Size of input buffer */
  633. #define OBUF   80        /* Size of output buffer */
  634. #define RSP  1000        /* Size of response buffer */
  635. #define SREC   80        /* Size of S-record buffer */
  636. /*
  637. ** Assorted pseudo-functions.
  638. */
  639. #define ASCII(c) ((c)&0x7F)
  640. #define Awrite(m) awrite(m)
  641. #define CTRL(c)  ((c)&0x1F)
  642. #define Dmp(a,s) dmp((long)(a),(long)(s))
  643. #define Pread(c,p,s) pread((int)(c),(char*)(p),(int)(s))
  644. #define Pwrite(p)    pwrite((char*)(p))
  645. #define Resync       resync()
  646. #define Slowly         if (slowfl) slowly()
  647. /*
  648. ** These might be in some standard libraries:
  649. */
  650. #define islower(c) ('a'<=(c)&&(c)<='z')
  651. #define isupper(c) ('A'<=(c)&&(c)<='Z')
  652. #define htob(c) ((('0'<=c)&&(c<='9'))?(c-'0'):\
  653.                  (('A'<=c)&&(c<='F'))?(c-'A'+10):\
  654.                  (('a'<=c)&&(c<='f'))?(c-'a'+10):-1)
  655. /*
  656. ** Limit type codes:
  657. */
  658. #define L_READS        10
  659. #define L_ES        2
  660. #define L_TC        3
  661. #define L_DL        4
  662. #define L_LOAD        4
  663. #define L_RX        5
  664. #define L_START        6
  665. #define L_TRIES         10
  666. /*
  667. ** Misc constants:
  668. */
  669. #define READS      3    /* Read attempts before failure */
  670. #define NUDGES     5    /* Nudge attempts before failure */
  671. #define EGARBAGE 101
  672. #define ETIMEOUT 102
  673. #define THRESH     3    /* Number of failures that elicits prompt */
  674. /*
  675. ** Sleep times for various routines.
  676. */
  677. #define SLEEP1    1
  678. #define SLEEP2    1
  679. #define SLEEP3    1
  680. #define SLEEPR    1
  681. #define SLEEPF    10
  682. #define SLEEPL    10
  683. /*
  684. ** Pseudo-commands.
  685. */
  686. #define Dead        goto dead
  687. #define Response    goto response
  688. #define Nudge        goto nudge
  689. /*
  690. ** Pseudo-types.
  691. */
  692. #define uint unsigned int
  693. /*
  694. ** Assorted messages.
  695. */
  696. extern char m_CTRLA [];
  697. extern char*m_exit;
  698. extern char m_login [];
  699. extern char m_passwd[];
  700. extern char*m_init;
  701. extern char*m_init1;
  702. extern char*m_init2;
  703. extern char*m_init3;
  704. extern char*m_nudge;
  705. /*
  706. ** Assorted global function typess.
  707. */
  708. extern char        * ctime();
  709. extern char        * gestate();
  710. extern char        * getime();
  711. extern char        * lastfield();
  712. extern struct utmp * findutmp();
  713. /*
  714. ** Assorted global variables.
  715. */
  716. extern uint  count;        /* Delay between "typed" chars */
  717. extern char *ctime();        /* Time in ASCII format */
  718. extern long  currtime;        /* Timestamp */
  719. extern char *ctimep;        /* Current ctime() value */
  720. extern char *device;        /* Name of serial port */
  721. extern int   dev;        /* Number of serial port file */
  722. extern char *devfld;        /* Last field of device name */
  723. extern Flag  echofl;        /* True if input is to be echoed */
  724. extern Flag  echoing;        /* True if input is being echoed */
  725. extern int   eol0;        /* Alternate EOL character */
  726. extern int   exitstat;        /* Status to report to exit() */
  727. extern int   files;        /* Number of files processed */
  728. extern Flag  forkfl;
  729. extern char  ibuf[IBUF];    /* Buffer for input from port */
  730. extern char *ibfa;        /* First valid char of ibuf */
  731. extern char *ibfz;        /* Last+1 valid char of ibuf */
  732. extern int   iomask;        /* Constant to convert values to ASCII */
  733. extern int   l_tries;        /* Number of reads between nudges */
  734. extern int   l_reads;        /* Number of reads before timeout */
  735. extern Flag  locked;        /* True if lockfile exists*/
  736. extern Flag  lockfl;        /* Create lockfile on login */
  737. extern int   lockfn;        /* Lockfile number */
  738. extern char  lockfile[50];    /* Place to build lockfile name */
  739. extern char  lockroot[];    /* Pathname for creating lockfiles */
  740. extern int   nudges;        /* Number of times we've nudged */
  741. extern int   Nudges;        /* Limit to nudge attempts */
  742. extern int   lsleep;        /* Sleep time for locks */
  743. extern char *oldtarg;        /* Previous name of target */
  744. extern char *path;        /* Default search path */
  745. extern Flag  pathfl;
  746. extern int   pid;        /* Our process id number */
  747. extern char *prgnam;        /* Last field of program's name */
  748. extern Flag  raw;        /* True if I/O is to be raw */
  749. extern char  rsp[1+RSP];    /* Response buffer */
  750. extern uint  rspmax;        /* Max response we can handle */
  751. extern uint  rspsiz;        /* Current size of response buffer */
  752. extern Flag  slow;        /* True if output should be slow */
  753. extern Flag  slowfl;        /* True if count or slow turned on */
  754. extern int   ss;        /* State: code for last action */
  755. extern char *target;        /* Name of thing on other side of port */
  756. extern Flag  termfl;        /* True if terminal state changed */
  757. extern struct termio trminit;    /* Initial ioctl() setting for device */
  758. extern uint  timeout;        /* Global timeout interval */
  759. /*
  760. ** User identification stuff:
  761. */
  762. #define PASSWD 16        /* Max length of a passwd */
  763. #define USERID 16        /* Max length of a userid */
  764. extern char  passwd[1+PASSWD];    /* Current passwd */
  765. extern char  userid[1+USERID];    /* Current userid */
  766. extern int   euid;        /* Effective user id number */
  767. extern int   ruid;        /* Real user id number */
  768. extern int   egid;        /* Effective group id number */
  769. extern int   rgid;        /* Real group id number */
  770. /*
  771. ** Definitions of non-int-valued functions:
  772. */
  773. struct utmp *findutmp();
  774. struct utmp *findutmp();
  775.        char *getime();
  776.        char *lastfield();
  777. /*
  778. ** Some common gotos:
  779. */
  780. #define Done goto done
  781. #define Fail goto fail
  782. #define Loop goto loop
  783.  
  784. #ifdef SYS5
  785. #endif
  786.  
  787. #define uutty_h
  788. #endif
  789. \!Funky\!Stuff\!
  790. echo file: dbg.h
  791. cat > dbg.h << '\!Funky\!Stuff\!'
  792. #ifndef dbg_h
  793. #include <stdio.h>
  794. #include <sys/types.h>
  795. /*
  796. ** The global 'debug' variable controls the level of diagnostics
  797. ** to be produced.  Some suggested conventions are:
  798. **    debug=0    fatal error messages only.
  799. **    debug=1    diagnostic: serious messages and warnings, default.
  800. **    debug=2    informative: major events and decisions.
  801. **    debug=3    gabby: tracing of likely trouble spots.
  802. **    debug=4    tracing of important events for troubleshooting.
  803. **    debug=5    major function calls and returns.
  804. **    debug=6    details of flow of control.
  805. **    debug=7    major data tracing.
  806. **    debug=8    detailed data tracing.
  807. **    debug=9    everything of conceivable interest to anyone.
  808. ** Of course, it is entirely up to you how you use the debug 
  809. ** level, and many applications won't have a need for 10 levels. 
  810. ** It will help others trying to use your code if they can use
  811. ** the debug level easily to find out what's wrong.  At level
  812. ** 1, in particular, it is a good idea to give enough info to
  813. ** tell the user what went wrong.  For instance, don't just say
  814. ** that you can't write to a file; show the pathname that you
  815. ** failed to open for writing, and the errno code (even better,
  816. ** give the sys_errlist[errno] message).
  817. */
  818. typedef          char  Flag;
  819. typedef unsigned char  U8;
  820. typedef unsigned short U16;
  821. typedef unsigned long  U32;
  822. /*
  823. ** Main debug-message pseudo-functions:
  824. */
  825. #define D  if(debug> 1)dmsg
  826. #define D1 if(debug>=1)dmsg
  827. #define D2 if(debug>=2)dmsg
  828. #define D3 if(debug>=3)dmsg
  829. #define D4 if(debug>=4)dmsg
  830. #define D5 if(debug>=5)dmsg
  831. #define D6 if(debug>=6)dmsg
  832. #define D7 if(debug>=7)dmsg
  833. #define D8 if(debug>=8)dmsg
  834. #define D9 if(debug>=9)dmsg
  835. #define E emsg
  836. #define P pmsg
  837. #define V if(debug>0)pmsg
  838. #define W wmsg
  839. /*
  840. ** These functions produce a 1-line dump, with non-printable
  841. ** characters converted to 2-char escape sequences.
  842. */
  843. #define Ascdump(a,n,o,m) ascdump((char*)(a),(U32)(n),(U32)(o),(char*)(m))
  844. #define Ascdp(a,p)     Ascdump(a,p-a+1,a,0) 
  845. #define Ascdn(a,n)     Ascdump(a,n,a,0) 
  846. #define Ascdpm(a,p,m)    Ascdump(a,p-a+1,0,m)
  847. #define Ascdnm(a,n,m)    Ascdump(a,n,0,m)
  848. /*
  849. ** These functions produce a 3-line dump, consisting of displayable
  850. ** characters, high-order hex digit, and low-order hex digit.  On
  851. ** the first line, non-printing characters are shown as '_'.
  852. */
  853. #define Hexdump(a,n,o,m) hexdump((char*)(a),(U32)(n),(U32)(o),(char*)(m))
  854. #define Hexdp(a,p)     Hexdump(a,p-a+1,a,0) 
  855. #define Hexdn(a,n)     Hexdump(a,n,a,0) 
  856. #define Hexdpm(a,p,m)    Hexdump(a,p-a+1,0,m)
  857. #define Hexdnm(a,n,m)    Hexdump(a,n,0L,m)
  858.  
  859. extern int   ascdump();    /* The actual ASCII-dump routine */
  860. extern char *crlf;    /* Line terminator string, usually "\n" */
  861. extern int   debug;    /* Debug level, 0-9, default=1 */
  862. extern int   dbgsleep;    /* Sleep time after output, default=0 */
  863. extern FILE *dbgout;    /* Diagnostic output stream, default=stderr */
  864. extern int   dsp();    /* Convert an int to a printable char */
  865. extern char *dbgtimep;    /* Time to display in debug messages */
  866. extern int   errno;    /* Unix global error code */
  867. extern int   hexdump();    /* The actual hex-dump routine */
  868. extern char *progname;    /* Name of running program, from argv[0] */
  869.  
  870. #define dbg_h
  871. #endif
  872. \!Funky\!Stuff\!
  873. echo file: args.c
  874. cat > args.c << '\!Funky\!Stuff\!'
  875. #include "uutty.h"
  876. /*
  877. ** Process the command-line arguments.
  878. */
  879. args(ac,av)
  880. char **av;
  881. {    int  a;
  882.  
  883.     for (a=1; a<ac; a++) {
  884.         D3("arg %d=\"%s\"",a,av[a]);
  885.         switch (av[a][0]) {
  886.         case '-':
  887.         case '+':
  888.             D6("opt %d=\"%s\"",a,av[a]);
  889.             option(av[a]);
  890.             continue;
  891.         default:
  892.             switch(files++) {
  893.             case 0:        /* Name of serial port */
  894.                 device = av[a];
  895.                 break;
  896.             default:
  897.                 E("Too many args; \"%s\" ignored.",av[a]);
  898.             }
  899.         }
  900.     }
  901. }
  902. \!Funky\!Stuff\!
  903. echo file: awrite.c
  904. cat > awrite.c << '\!Funky\!Stuff\!'
  905. #include "uutty.h"
  906. /* 
  907. ** Write a character string to the port, stopping at the first null,
  908. ** and processing a variety of escape sequences.  This routine always
  909. ** writes one byte at a time.  Doing a system call per byte is a bit
  910. ** wasteful of processor time, but it helps assure that we won't flood
  911. ** the poor little helpless modem.
  912. */
  913. #define Gotbyte goto gotbyte 
  914.  
  915. awrite(msg)
  916.     char*msg;
  917. {    int  i, n;
  918.     char c, d, *p;
  919.  
  920.     D5("awrite(%08lX)",msg);
  921.     if (debug) {
  922.         dbgtimep = getime();
  923.         if (debug >= 2) P("%s Send:   %s",dbgtimep,msg);
  924.         if (debug >= 4) Hexdnm(msg,1,"Send:");
  925.     }
  926.     n = strlen(msg);
  927.     D8("port_wr:slow=%d",slow);
  928.     p = msg;
  929.     while (c = *p++) {
  930.         switch (c) {
  931.         case '^':        /* CTRL-X notation */
  932.             c = *p++ & 0x3F;
  933.             Gotbyte;
  934.         case '%':        /* %AB is a hex value */
  935.             c = 0;
  936.             n = 2;        /* Accept at most 2 digits */
  937.             while (n-- > 0) {
  938.                 switch (d = *p) {
  939.                 case '9': case '8': case '7': case '6': case '5': 
  940.                 case '4': case '3': case '2': case '1': case '0':
  941.                     c = (c << 4) | (c - '0');
  942.                     Gotbyte;
  943.                 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  944.                     c = (c << 4) | (c - 'A' + 10);
  945.                     Gotbyte;
  946.                 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  947.                     c = (c << 4) | (c - 'a' + 10);
  948.                     Gotbyte;
  949.                 default:
  950.                     goto gotbyte;
  951.                 }
  952.                 ++p;
  953.             }
  954.             Gotbyte;
  955.         case '\\':        /* Escape notation */
  956.             switch (c = *p++) {
  957.             case '7': case '6': case '5': case '4':
  958.             case '3': case '2': case '1': case '0':
  959.                 c -= '0';
  960.                 if ((d = *p) && ('0'<=d && d<='7')) {
  961.                     c = (c << 3) | (d - '0');
  962.                     ++p;
  963.                     if ((d = *p) && ('0'<=d && d<='7')) {
  964.                         c = (c << 3) | (d - '0');
  965.                         ++p;
  966.                     }
  967.                 }
  968.                 Gotbyte;
  969.             case 'B': case 'b': c = '\b'; Gotbyte;
  970.             case 'D': case 'd': sleep(1); continue;
  971.             case 'N': case 'n': c = '\n'; Gotbyte;
  972.             case 'R': case 'r': c = '\r'; Gotbyte;
  973.             case 'T': case 't': c = '\t'; Gotbyte;
  974.             case 'X': case 'x': sendbrk(dev); continue;
  975.             default : c = d; Gotbyte;
  976.             }
  977.         }
  978. gotbyte:    Slowly;
  979.         if (debug >= 3) {
  980.             dbgtimep = getime();
  981.             if (debug >= 3) Ascdnm(&c,1,"Write:");
  982.             if (debug >= 4) Hexdnm(&c,1,"Write:");
  983.         }
  984.         D4("awrite: c=%02X='%c'",c,dsp(c));
  985.         D9("port_wr:before write(%d,%06lX,%d)",dev,&c,1);
  986.         i = write(dev,&c,1);
  987.         D9("port_wr: after write(%d,%06lX,%d)=%d",dev,&c,1,i);
  988.         if (i <= 0) {
  989.             if (debug) P("%s: write failed, quitting.",getime());
  990.             die(2);
  991.         }
  992.     }
  993. }
  994. \!Funky\!Stuff\!
  995. echo file: checkid.c
  996. cat > checkid.c << '\!Funky\!Stuff\!'
  997. #include "uutty.h"
  998. /* 
  999. ** The response string is believed to contain a login id.
  1000. ** The id is copied to the global variable "userid", and
  1001. ** its length returned.
  1002. */
  1003. checkid(rp)
  1004.     char *rp;
  1005. {    char *p, *q;
  1006.  
  1007.     D4("checkid: r=\"%s\" ss=%d",rp,ss);
  1008.     for (p=rp; *p; ++p) {    /* Examine the chars for acceptability */
  1009.         switch(*p) {
  1010.         case 0x04:        /* EOT triggers a login prompt */
  1011.             Pwrite("login:");
  1012.             target = "?";
  1013.             ss = S_LOGIN;
  1014.             D4("State %d=%s",ss,gestate());
  1015.             return 1;
  1016.         case ' ':        /* Blanks aren't legal */
  1017.         case ':':        /* Colons aren't legal */
  1018.         case '\b':        /* Backspaces aren't legal */
  1019.         case '\t':        /* Tabs aren't legal */
  1020.             D3("ID with whitespace ignored.");
  1021.             ss = S_IDLE;
  1022.             D4("State %d=%s",ss,gestate());
  1023.             Fail;
  1024.         case '\0':        /* Assorted terminal chars */
  1025.         case '\r':
  1026.         case '\n':
  1027.             *p = 0;
  1028.             goto good;
  1029.         case '!':        /* Special goodie for killing daemon */
  1030.             if (p[1] == 'Q') {
  1031.                 E("!Q in input; ");
  1032.                 if (debug) P("%s: !Q in input, quitting [id]",getime());
  1033.                 die(0);
  1034.             }
  1035.         default:
  1036.             continue;
  1037.         }
  1038.     }
  1039. good:            /* Make a copy of the supposed id */
  1040.     p = rp;
  1041.     q = userid;
  1042.     while (*p && q<userid+USERID)
  1043.         *q++ = *p++;
  1044.     *q = 0;
  1045.     if (debug >= 2) P("%s USERID=\"%s\"",getime(),userid);
  1046.     target = "logger";
  1047.     return (p-rp);
  1048. fail: return 0;
  1049. }
  1050. \!Funky\!Stuff\!
  1051. echo file: copy.c
  1052. cat > copy.c << '\!Funky\!Stuff\!'
  1053. /* Copy *s to *t, n bytes.
  1054. */
  1055. copy(t,s,n)
  1056.  char *t, *s;
  1057.  int   n;
  1058. {
  1059.     while (n-- > 0)
  1060.         *t++ = *s++;
  1061. }
  1062. \!Funky\!Stuff\!
  1063. echo file: data.c
  1064. cat > data.c << '\!Funky\!Stuff\!'
  1065. #include "uutty.h"
  1066. #include <signal.h>
  1067.  
  1068. /*
  1069. ** Assorted messages.
  1070. */
  1071. char*m_exit = 0;            /* May be set to special exit message */
  1072. char m_login [] = "\r\nlogin:";        /* Unix login prompt */
  1073. char m_passwd[] = "\r\npassword:";    /* Unix password prompt */
  1074. char*m_init     = 0;            /* Special init string for device */
  1075. char*m_init1    = 0;            /* May be set to special init message */
  1076. char*m_init2    = "\r";            /* Normal nudge to get first response */
  1077. char*m_init3    = 0;            /* May be set to special init message */
  1078. char*m_nudge    = "\r";            /* What to send to trigger a response */
  1079. /*
  1080. ** Assorted global variables.
  1081. */
  1082. int   baudmask = 0;    /* CBAUD mask for termio ioctl (B1200, B9600, etc) */
  1083. int   baudrate = 0;    /* Numeric value of baud rate (1200, 9600, etc) */
  1084. uint  count  = 0;    /* Delay between "typed" chars */
  1085. long  currtime;        /* Timestamp */
  1086. char *ctimep = "?";    /* ASCII form of currtime */
  1087. char *device = 0;    /* Name of serial port */
  1088. int   dev    = 0;    /* Number of serial port */
  1089. char *devfld= "?";    /* Last field of device name */
  1090. Flag  echofl = 0;    /* True if input is to be echoed */
  1091. Flag  echoing= 0;    /* True if input is being echoed */
  1092. int   eol0   = -1;    /* Extra EOL char to recognize */
  1093. int   exitstat = 0;
  1094. int   files  = 0;
  1095. char  ibuf[IBUF];    /* Buffer for input from port */
  1096. char *ibfa   = ibuf;    /* First valid char of ibuf */
  1097. char *ibfz   = ibuf;    /* Last+1 valid char of ibuf */
  1098. int   iomask = 0x7F;    /* Converts chars to ASCII */
  1099. int   l_tries= L_TRIES;    /* Number of reads between nudges */
  1100. int   l_reads= L_READS;    /* Number of reads before timeout */
  1101. int   lsleep = 30;    /* Sleep time when we hit a lockfile */
  1102. Flag  locked = 0;    /* Lockfile created */
  1103. Flag  lockfl = 0;    /* Create lockfile on login */
  1104. int   lockfn = -1;    /* Lockfile number */
  1105. char  lockfile[50] = {0};    /* Place to build lockfile name */
  1106. char  lockroot[] = "/usr/spool/uucp/LCK..";
  1107. int   nudges = 0;    /* Number of times we've nudged */
  1108. int   Nudges = NUDGES;    /* Limit to nudge attempts */
  1109. char *oldtarg = "?";    /* Previous name for thing on other side of port */
  1110. int   pid    = -1;    /* Our process id number */
  1111. char *prgnam = "?";    /* Last field of program's name */
  1112. Flag  raw    = 1;    /* Raw I/O on device? */
  1113. char  rsp[1+RSP];    /* Response buffer */
  1114. uint  rspmax = RSP;    /* Max response we can handle */
  1115. Flag  slow   = 0;
  1116. Flag  slowfl = 0;    /* True if count or slow turned on */
  1117. int   ss     = S_INIT;    /* State: code for last action */
  1118. char *target  = "port";    /* Name of thing on other side of port */
  1119. Flag  termfl  = 0;    /* True if terminal state changed */
  1120. /*
  1121. ** User identification stuff:
  1122. */
  1123. char  passwd[1+PASSWD] = {0};    /* Current passwd */
  1124. char  userid[1+USERID] = {0};    /* Current userid */
  1125. int   euid    = -1;        /* Effective user id number */
  1126. int   ruid    = -1;        /* Real user id number */
  1127. int   egid    = -1;        /* Effective group id number */
  1128. int   rgid    = -1;        /* Real group id number */
  1129.  
  1130. #ifdef SYS5
  1131.     struct stat   status;        /* Child process's status */
  1132.     struct termio trminit  = {0};    /* For saving terminal (ioctl) status */
  1133.     struct utmp  *up = 0;        /* Pointer to /etc/utmp entry */
  1134.     struct utmp   utmp = {0};    /* Scratch /etc/utmp entry */
  1135. #endif
  1136.  
  1137. \!Funky\!Stuff\!
  1138. echo file: dbg.c
  1139. cat > dbg.c << '\!Funky\!Stuff\!'
  1140. /* John Chambers' debugging package for C programs.  This
  1141. ** package is intended, among other things, to be added to
  1142. ** other peoples' software after the fact to aid in getting
  1143. ** it to run.  An attempt has been made to avoid global 
  1144. ** names that others will use, though there are likely
  1145. ** to be collisions with other debugging packages.  The
  1146. ** most common source of conflicts is due to the fact that
  1147. ** this package includes <stdio.h> and <sys/types.h>; you
  1148. ** should hunt down references to either of these and put
  1149. ** the line:
  1150. **    #include <dbg.h>
  1151. ** in place of both of them.
  1152. **
  1153. ** The primary functions defined here are based on conditional 
  1154. ** calls of printf(), with the program's name inserted at the 
  1155. ** start, a newline appended, and fflush() called to send it 
  1156. ** on its way.  There is also a hexdump() routine to produce
  1157. ** a hex dump of a chunk of memory, and an ascdump() routine
  1158. ** to display things in ASCII form.  All these are intended 
  1159. ** to be called via the macros defined in "dbg.h".
  1160. **
  1161. ** The global variable "debug" should be set to a value in [0,9],
  1162. ** to control the amount of debugging output.
  1163. **
  1164. ** Note that "dbgout" is a FILE*, either stdout or stderr as you
  1165. ** wish, with stderr the default.
  1166. */
  1167. #include "dbg.h"
  1168.  
  1169. static char dbgheader[] = "@(#)RELEASE: 1.0  Sep 20 1986 ~jc/dbg";
  1170. /* 
  1171. ** If you normally use terminals with a particular line
  1172. ** length, you might adjust these.  Note that there is
  1173. ** an initial 7-byte fieldin all lines, plus a newline,
  1174. ** so MAXCOLS should be >= MAXCHS+8.
  1175. */
  1176. #define MAXCOLS 80        /* Max length of print line */
  1177. #define MAXCHRS 64        /* Max chars in one hexdump chunk */
  1178.  
  1179. extern int errno;            /* Unix error code */
  1180.     char  *crlf   = "\n";        /* Line terminator string, might be "\n\r" */
  1181.     FILE  *dbgout = stderr;        /* Can be assigned to switch to stdout */
  1182.     int    dbgsleep = 0;        /* Sleep time (secs) after messages */
  1183.     int    debug  = 1;        /* Set to desired debug level (0-9) */
  1184.     char *dbgtimep  = 0;        /* Set to ASCII date/time if desired in output */
  1185. static    int    hex_chrs = MAXCHRS;    /* Number of chars to dump in one line */
  1186. static    int    hex_cols = MAXCOLS;    /* Length of print line */
  1187. static    int    hex_word = MAXCHRS;    /* Number of bytes to group together */
  1188.     char  *progname = "?";        /* Set to argv[0] */
  1189. /*
  1190. ** Debug output routine.  The program's name is
  1191. ** prepended to the message, a terminator is added,
  1192. ** and an optional sleep is done.
  1193. */
  1194. /*VARARGS1*//*ARGSUSED*/
  1195. dmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
  1196. {    int n;
  1197.     n  = fprintf(dbgout,"%s: ",progname);
  1198.     n += fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  1199.     n += fprintf(dbgout,crlf);
  1200.     fflush(dbgout);
  1201.     if (dbgsleep) sleep(dbgsleep);
  1202.     return n;
  1203. }
  1204. /* Note that emsg() writes to both dbgout and stderr.
  1205. */
  1206. /*VARARGS1*//*ARGSUSED*/
  1207. emsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
  1208. {   int n;
  1209.     if (dbgout != stderr)
  1210.         n = dmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  1211.     n += fprintf(stderr,"%s: ",progname);
  1212.     n += fprintf(stderr,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  1213.     n += fprintf(stderr,crlf);
  1214.     fflush(stderr);
  1215.     return n;
  1216. }
  1217. /* Print a message to the debug output, adding only
  1218. ** a terminator, but don't add program identification.
  1219. */
  1220. /*VARARGS1*//*ARGSUSED*/
  1221. pmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
  1222. {   int n;
  1223.     n  = fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  1224.     n += fprintf(dbgout,crlf);
  1225.     fflush(dbgout);
  1226.     if (dbgsleep) sleep(dbgsleep);
  1227.     return n;
  1228. }
  1229. /* Write a message to the debug output, adding nothing.
  1230. */
  1231. /*VARARGS1*//*ARGSUSED*/
  1232. wmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
  1233. {   int n;
  1234.     n  = fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  1235.     fflush(dbgout);
  1236.     if (dbgsleep) sleep(dbgsleep);
  1237.     return n;
  1238. }
  1239. /* 
  1240. ** Hexdump routine.  The params are a starting address,
  1241. ** a byte count, an address to show on the output (which 
  1242. ** is often the starting address), and an optional message
  1243. ** for labeling the dump.  If the message is present, the
  1244. ** address is not displayed, since they both would appear
  1245. ** at the same place in the output.
  1246. **
  1247. ** Note that the actual output is done by pmsg().
  1248. */
  1249. static char  hex_cc[1+MAXCOLS];
  1250. static char  hex_hi[1+MAXCOLS];
  1251. static char  hex_lo[1+MAXCOLS];
  1252. static int   ascfl = 0;            /* True if hex dump not wanted */
  1253. /*
  1254. ** Produce only the ASCII line; omit the two hex lines.
  1255. */
  1256. ascdump(a,n,o,m)
  1257.     char *a;    /* Address of first byte to dump */
  1258.     U32   n;    /* Number of bytes */
  1259.     char *o;    /* Offset (address) to report */
  1260.     char *m;    /* Initial message, if o==NUL */
  1261. {    int   c;
  1262.  
  1263.     D4("ascdump(a=%06lX,n=%d,o=%06lX,m=%06lX)",a,n,o,m);
  1264.     if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
  1265.     if (m) sprintf(hex_cc,"%s            ",m);
  1266.       else sprintf(hex_cc,"%7d           ",o);
  1267.     fprintf(dbgout,"%7.7s",hex_cc);
  1268.     fflush(dbgout);
  1269.     while (n-- > 0) {
  1270.       c = *a++ & 0x7F;
  1271.       switch (c) {
  1272.       case '\0': fprintf(dbgout,"\\0"); break;
  1273.       case '^' : fprintf(dbgout,"\\^"); break;
  1274.       case '\\': fprintf(dbgout,"\\\\"); break;
  1275.       case '\b': fprintf(dbgout,"\\b"); break;
  1276.       case '\n': fprintf(dbgout,"\\n"); break;
  1277.       case '\r': fprintf(dbgout,"\\r"); break;
  1278.       case '\t': fprintf(dbgout,"\\t"); break;
  1279.       case 0x7F: fprintf(dbgout,"\\D"); break;
  1280.       default: 
  1281.         if (c < ' ') {
  1282.           fprintf(dbgout,"^%c",c|0x40);
  1283.           break;
  1284.         }
  1285.         fprintf(dbgout,"%c",c);
  1286.         break;
  1287.       }
  1288.     }
  1289.     fprintf(dbgout,crlf);
  1290.     fflush(dbgout);
  1291. }
  1292. /*
  1293. */
  1294. hexdump(a,n,o,m)
  1295.     char *a;    /* Address of first byte to dump */
  1296.     U32   n;    /* Number of bytes */
  1297.     U32   o;    /* Offset (address) to report */
  1298.     char *m;    /* Initial message, if o==NUL; -1 for ascii only */
  1299. {
  1300.     ascfl = 0;
  1301.     return hex_dump(a,n,o,m);
  1302. }
  1303. /*
  1304. */
  1305. hex_dump(a,n,o,m)
  1306.     char *a;    /* Address of first byte to dump */
  1307.     U32   n;    /* Number of bytes */
  1308.     U32   o;    /* Offset (address) to report */
  1309.     char *m;    /* Initial message, if o==NUL; -1 for ascii only */
  1310. {    int   col, i;
  1311.     char  c;
  1312.  
  1313.     hex_init(m,o);
  1314.     col = 0;
  1315.     while (n) {    
  1316.         c = *a++;
  1317.         i = 7 + col + (col / hex_word);
  1318.         n--;
  1319.         hex_lo[i] = hex_dig(c & 0xF);
  1320.         hex_hi[i] = hex_dig((c >> 4) & 0xF);
  1321.         hex_cc[i] = dsp(c);
  1322.         col++;
  1323.         o++;
  1324.         if (col >= hex_chrs) {    
  1325.             hex_out();
  1326.             hex_init(m,o);
  1327.             col = 0;
  1328.         }
  1329.     }
  1330.     if (col > 0) hex_out();
  1331.     return 0;
  1332. }
  1333. /* Generate a printable char for x.  If x is an ASCII
  1334. ** printable char, it is returned.  For others, '_' is
  1335. ** returned.
  1336. */
  1337. dsp(x) 
  1338. {    x &= 0x7F;
  1339.     return (0x20<=x && x<=0x7E) ? x : '_';
  1340. }
  1341. /* Given a small integer [0-15], this routine returns
  1342. ** the corresponding ASCII char for a hex digit.
  1343. */
  1344. hex_dig(x) 
  1345. {    return  ( 0<=x && x<= 9) ? '0' + x 
  1346.     : (10<=x && x<=15) ? 'A' + x - 10 
  1347.     : '_';
  1348. }
  1349. /* Initialize the line images for a given address.
  1350. */
  1351. hex_init(m,a)
  1352.     char *m;    /* Initial message (<=8 chars) */
  1353.     U32   a;    /* Address reported on output */
  1354. {    int   i;
  1355.  
  1356.     i = hex_chrs + (hex_chrs / hex_word) + 8;    /* Length of print line (including final newline) */
  1357.     if (hex_cols < i) {
  1358.         hex_cols = i;
  1359.         D5("hex_init: cols=%d chrs=%d word=%d",hex_cols,hex_chrs,hex_word);
  1360.     }
  1361.     for (i=0; i<=hex_cols; i++)
  1362.         hex_cc[i] = hex_hi[i] = hex_lo[i] = ' ';
  1363.     if (m && a==0) {
  1364.         strcpy(hex_cc,m);
  1365.     } else {
  1366.         sprintf(hex_cc,"%6ld: ",a);
  1367.         sprintf(hex_hi,"%6lX: ",a);
  1368.     }
  1369.     return 0;
  1370. }
  1371. /* The three lines of hex dump info are complete;
  1372. ** do a bit of straightening out, and print them.
  1373. */
  1374. hex_out()
  1375. {    int i;
  1376.  
  1377.     for (i=0; i<=hex_cols; i++) {        /* sprintf() may produce nulls */
  1378.         if (hex_cc[i] == 0) hex_cc[i] = ' ';
  1379.         if (hex_hi[i] == 0) hex_hi[i] = ' ';
  1380.         if (hex_lo[i] == 0) hex_lo[i] = ' ';
  1381.     }
  1382.     for (i=hex_cols; i>0; i--)             /* Trim lines */
  1383.         if (hex_cc[i] == ' ') 
  1384.             hex_cc[i] = 0;
  1385.         else break;
  1386.     for (i=hex_cols; i>0; i--) 
  1387.         if (hex_hi[i] == ' ') 
  1388.             hex_hi[i] = 0;
  1389.         else break;
  1390.     for (i=hex_cols; i>0; i--) 
  1391.         if (hex_lo[i] == ' ') 
  1392.             hex_lo[i] = 0;
  1393.         else break;
  1394.     if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
  1395.     pmsg("%s",hex_cc);            /* Symbolic dump */
  1396.     if (ascfl == 0) {
  1397.         if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
  1398.         pmsg("%s",hex_hi);        /* High-order hex digit */
  1399.         if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
  1400.         pmsg("%s",hex_lo);        /* Low-order hex digit */
  1401.     }
  1402.     if (dbgsleep) sleep(dbgsleep);
  1403.     return 0;
  1404. }
  1405. \!Funky\!Stuff\!
  1406. echo file: die.c
  1407. cat > die.c << '\!Funky\!Stuff\!'
  1408. #include "uutty.h"
  1409. #include <signal.h>
  1410.  
  1411. die(retval)
  1412. {    int i;
  1413.  
  1414.     D4("die(%d)",retval);
  1415.     if (locked) unlock();
  1416.     l_tries = l_reads = 1;    /* Give up quickly */
  1417.     Resync;            /* Gobble up all input */
  1418.     if (m_exit) Awrite(m_exit);    /* Special exitial message? */
  1419.     if (termfl && isatty(dev)) {    /* Restore terminal status */
  1420.         D7("die: %d:\tcflag=%06o",dev,trminit.c_cflag);
  1421.         D7("die: %d:\tiflag=%06o",dev,trminit.c_iflag);
  1422.         D7("die: %d:\tlflag=%06o",dev,trminit.c_lflag);
  1423.         D7("die: %d:\toflag=%06o",dev,trminit.c_oflag);
  1424.         D5("die:before ioctl(%d,%d,%06lX)",dev,TCSETA,&trminit);
  1425.         i = ioctl(dev,TCSETA,&trminit);
  1426.         D5("die: after ioctl(%d,%d,%06lX)=%d",dev,TCSETA,&trminit,i);
  1427.         D3("File %d restored to normal.",dev);
  1428.     }
  1429.     exit(retval);
  1430. }
  1431. \!Funky\!Stuff\!
  1432. echo file: exec.c
  1433. cat > exec.c << '\!Funky\!Stuff\!'
  1434. #include "uutty.h"
  1435. /* 
  1436. ** Start up a new program in the current process.  This is normally
  1437. ** to start up a shell for a logged-in user.   If the command can't
  1438. ** be executed, -1 is returned.     Note that we can define a new search
  1439. ** path here which will overwrite the one we were given.
  1440. */
  1441.     Flag  forkfl = 0;    /* Should we fork or exec directly? */
  1442.     Flag  pathfl = 0;    /* True if PATH defined in environment */
  1443. /*
  1444. ** The 'path' variable should be defined appropriately for your
  1445. ** system.  If it is null, we will just pass on the path that
  1446. ** was handed to us, which may be right on many systems.
  1447. */
  1448. #ifdef Cadmus
  1449.     char *path = "PATH=:.:/bin:/bin.cadmus:/bin.sys5:/bin.sys3:/bin.ver7:/usr/ucb:/usr/bin:/etc:/usr/local:/usr/new:";
  1450. #define Path
  1451. #endif
  1452. #ifdef VME
  1453.     char *path = "PATH=:.:/bin:/usr/bin:/etc:";
  1454. #define Path
  1455. #endif
  1456. #ifndef Path
  1457.     char *path = 0;        /* No search path */
  1458. #endif
  1459.  
  1460. exec(cook,cmd,pp)
  1461.     int   cook;        /* Should we do cooked or raw I/O? */
  1462.     char *cmd;        /* Null-terminated command */
  1463.     struct passwd *pp;    /* The user's /etc/passwd entry, unpacked */
  1464. {    int   a, c, e, i, n, r;
  1465.     int   child;
  1466.     Flag  lognfl, shelfl, homefl;
  1467.     char *av[10];        /* This should be room enough */
  1468.     char *cp, *dp;
  1469.     char**ev;
  1470.     char  arg0[30];        /* For shell's visible name */
  1471.     char  logn[30];        /* For LOGNAME=<id> string */
  1472.     char  home[30];        /* For HOME=<dir> string */
  1473.     char  shll[30];        /* For SHELL=<prog> string */
  1474.     char *shell="/bin/sh";    /* default shell */
  1475.     extern long malloc();
  1476.  
  1477.     D5("exec(%d,\"%s\",%06lX)",cook,cmd,pp);
  1478.     r = -1;
  1479.     for (i=0; environ[i]; i++);    /* How big is environ[]? */
  1480.     n = (i+5) * sizeof(char**);    /* Space for copy + 5 entries */
  1481.     D5("exec: Get %d bytes for %d+5 environment entries.",n,i);
  1482.     ev = (char**)malloc(n);        /* Allocate a copy for us */
  1483.     if (ev == NULL) {
  1484.         E("Can't get %d bytes for environment table [exec].",n);
  1485.         Fail;
  1486.     }
  1487.     for (e=0; environ[e]; e++) {    /* Copy the environment vector */
  1488.         ev[e] = environ[e];
  1489.         D6("ev[%2d]=\"%s\"",e,ev[e]);
  1490.     }
  1491.     ev[e] = 0;
  1492.     D3("exec: There are %d environment entries.",e);
  1493.     pid = getpid();
  1494.     D4("exec: This is process %d.",pid);
  1495.     a = e = 0;            /* indices for av[] and ev[] */
  1496.     for (cp=cmd; *cp; ++cp) {    /* Scan the command for whitespace */
  1497.         c = *cp;
  1498.         if (c == ' ' || c == '\t') {
  1499.             av[a++] = "-sh";
  1500.             av[a++] = "-c";
  1501.             av[a++] = cmd;
  1502.             break;
  1503.         } else
  1504.         if (c == ':' || c == '\n') break;
  1505.     }
  1506.     if (a == 0) {                /* the command is just a program name */
  1507.         shell = cmd;            /* Note that it's our shell */
  1508.         dp = av[a++] = arg0;        /* Name to tell shell */
  1509.         *dp++ = '-';            /* Build arg0 with initial '-' */
  1510.         cp = lastfield(cmd,'/');    /* Find the last field of the name */
  1511.         while (*cp) *dp++ = *cp++;    /* Copy name to arg0 */
  1512.         *dp = 0;            /* Gotta have a null terminator */
  1513.         D4("exec: arg0=\"%s\"",arg0);
  1514.     }
  1515.     D3("av[%2d]=\"%s\"",a-1,av[a-1]);
  1516.  
  1517.     D7("exec:before sprintf(%06lX,\"%s\",%06lX)",logn,"LOGNAME=%s\0",pp->pw_name);
  1518.     sprintf(logn,"LOGNAME=%s\0",pp->pw_name);
  1519.     D6("exec: after sprintf() logn=\"%s\"",logn);
  1520.  
  1521.     D7("exec:before sprintf(%06lX,\"%s\",%06lX)",home,"HOME=%s\0"   ,pp->pw_dir);
  1522.     sprintf(home,"HOME=%s\0"   ,pp->pw_dir);
  1523.     D6("exec: after sprintf() home=\"%s\"",home);
  1524.  
  1525.     D7("exec:before sprintf(%06lX,\"%s\",%06lX)",shll,"SHELL=%s\0"  ,shell);
  1526.     sprintf(shll,"SHELL=%s\0"  ,shell);
  1527.     D6("exec: after sprintf() shll=\"%s\"",shll);
  1528.  
  1529.     if (debug >= 5) {
  1530.         av[a++] = "-VX";        /* This turns on shell debugging */
  1531.         D3("av[%2d]=\"%s\"",a-1,av[a-1]);
  1532.     }
  1533.     av[a] = 0;            /* Paranoia */
  1534. /*
  1535. ** This is supposed to help, but seems not to:
  1536. **
  1537.     D4("exec: before setpgrp()");
  1538.     i = setpgrp();
  1539.     D4("exec: setpgrp()=%d",i);
  1540. */
  1541.     lognfl = shelfl = homefl = 0;        /* Flags for noticing environment entries */
  1542.     for (e=0; ev[e]; e++) {            /* Examine the environment table */
  1543.         D3("exec: Examine ev[%2d]=%06lX=\"%s\"",e,ev[e],ev[e]);
  1544.         if (st_init("PATH=",ev[e]) > 0) {
  1545.             D7("exec: Matched \"PATH=\"; path=%06lX=\"%s\"",path,path);
  1546.             if (path) ev[e] = path;    /* Use special path */
  1547.             D6("ev[%2d]=\"%s\"",e,ev[e]);
  1548.             pathfl++;        /* Note we did it */
  1549.         }
  1550.         if (st_init("LOGNAME=",ev[e]) > 0) {
  1551.             ev[e] = logn;        /* Use special path */
  1552.             D6("ev[%2d]=\"%s\"",e,ev[e]);
  1553.             lognfl++;        /* Note we did it */
  1554.         }
  1555.         if (st_init("HOME=",ev[e]) > 0) {
  1556.             ev[e] = home;        /* Use special path */
  1557.             D6("ev[%2d]=\"%s\"",e,ev[e]);
  1558.             homefl++;        /* Note we did it */
  1559.         }
  1560.         if (st_init("SHELL=",ev[e]) > 0) {
  1561.             ev[e] = shll;        /* Use special path */
  1562.             D6("ev[%2d]=\"%s\"",e,ev[e]);
  1563.             shelfl++;        /* Note we did it */
  1564.         }
  1565.     }
  1566.     if (!homefl) ev[e++] = home;    /* Add the home directory */
  1567.     if (!lognfl) ev[e++] = logn;    /* Add the login id */
  1568.     if (!shelfl) ev[e++] = shll;    /* Add the shell's name */
  1569.     if (!pathfl) ev[e++] = path;    /* Add the search path (may be null) */
  1570.     D3("exec: There are %d environment entries.",e);
  1571.     ev[e] = 0;            /* Paranoia */
  1572.     if (debug >= 3) {        /* Display the shell's parameters */
  1573.         P("before execve(\"%s\",%lX,%lX)",shell,av,ev);
  1574.         for (i=0; av[i]; i++)
  1575.             P("arg[%2d]=\"%s\"",i,av[i]);
  1576.         for (i=0; ev[i]; i++)
  1577.             P("env[%2d]=\"%s\"",i,ev[i]);
  1578.     }
  1579.     if (debug) P("%s Start %s for u=%d=%s g=%d.",getime(),shell,pp->pw_uid,pp->pw_name,pp->pw_gid);
  1580.     if (cook) makesane(dev);
  1581.     if (dev != 0) {close(0); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
  1582.     if (dev != 1) {close(1); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
  1583.     child = -1;            /* Default is no child process */
  1584.     pid = getpid();            /* Note which process we are now */
  1585.     if (forkfl) {            /* Are we forking or execing directly? */
  1586.         D4("exec: Forking sub-process for shell.");
  1587.         if (lockfl) {        /* Should we create a lockfile? */
  1588.             lockfn = creat(lockfile,0);
  1589.             if (debug >= 2)
  1590.                 P("%s: Create lockfile %d=\"%s\".",getime(),lockfn,lockfile);
  1591.             if (lockfn < 0) {    /* Either locked or directory isn't writable */
  1592.                 E("Can't create lockfile \"%s\" [errno=%d]",lockfile,errno);
  1593.                 die(errno);
  1594.             }
  1595.             locked = 1;        /* Note that there's a lockfile */
  1596.         }
  1597.         if ((child = fork()) > 0) {    /* Are we the parent? */
  1598.             D3("exec: %s: Shell process %d created.",getime(),child);    
  1599.             if (lsleep > 0) sleep(lsleep);
  1600.             for (;;) {        /* Loop until shell goes away */
  1601.                 errno = 0;
  1602.                 r = wait(0);        /* Sleep until a subprocess dies */
  1603.                 D3("%s: wait(0)=%d",getime(),r);
  1604.                 if (r == child)        /* Was it the shell process? */
  1605.                     Done;        /* If so, all's fine */
  1606.                 D3("%s: After wait(0)=%d [errno=%d]",getime(),r,errno);
  1607.                 if (r > 0) {
  1608.                     E("%s: Wrong child %d died; waiting for %d.",getime(),r,child);
  1609.                     continue;
  1610.                 }
  1611.                 switch(errno) {
  1612.                 case ECHILD:
  1613.                     D3("exec: wait(0)=%d [errno=%d=No child]",r,errno);
  1614.                     Done;
  1615.                 default:
  1616.                     E("Unknown errno=%d after wait(0)=%d",errno,r);
  1617.                     Done;
  1618.                 }
  1619.             }            /* Hang until the shell process dies */
  1620. done:            if (debug) sleep(1);
  1621.             D3("exec: %s: Child %d gone.",getime(),r);
  1622.             if (r > 0) r = 0;
  1623.             if (lockfl) unlock();
  1624.             if (debug) P("%s: \"%s\" done , die(%d)",getime(),shell,r);
  1625.             Fail;
  1626.         }
  1627.     }
  1628. /* 
  1629. ** If we fall through to here, we are the process to exec a shell.
  1630. ** We may be the original process or a subprocess.
  1631. */
  1632.     if (debug > 1) {
  1633.         pid = getpid();
  1634.         P("%s: Shell process %d.",getime(),pid);
  1635.     }
  1636.     if (dev != 2) { close(2); i = dup(dev); }
  1637.     /**** Don't produce debug output after this! */
  1638.     errno = 0;
  1639.     if (dev>2) close(dev);    /* Don't give excess open files to the shell */
  1640.     r = execve(shell,av,ev);
  1641.     E("Can't exec \"%s\"\t[errno=%d]",shell,errno);
  1642. /*
  1643. ** Note that we always terminate, regardless of how we get here.
  1644. ** If we are being run from init(1), a new process will be started
  1645. ** up.  If not, we just go away.  This isn't necessary, but seems
  1646. ** in general to be a good idea.
  1647. */
  1648. fail:                /* Both processes come here to terminate */
  1649.     if (lsleep > 0)
  1650.         sleep(lsleep);    /* Don't respawn too fast */
  1651.     die(r);            /* This will respawn if we're a daemon */
  1652. }
  1653. \!Funky\!Stuff\!
  1654. echo file: fillutmp.c
  1655. cat > fillutmp.c << '\!Funky\!Stuff\!'
  1656. #include "uutty.h"
  1657. /* 
  1658. ** The following routine may have to be changed for different Unices,
  1659. ** and probably will have to be totally rewritten for other systems.
  1660. **
  1661. ** Fill in fields of the utmp structure *up, which may be our global
  1662. ** utmp or may be another one returned by some library routine.
  1663. **
  1664. ** Here that we define our own cute copy macro, which copies <siz> 
  1665. ** bytes or to the first null, whichever comes first.  Note the test
  1666. ** to verify that the src address is nonnull.
  1667. */
  1668. #define CP(dst,src,siz) {p = dst; if (q = src) for (i=0; i<siz; i++) if (*q) *p++ = *q++; else *p++ = '\0';}
  1669.  
  1670. fillutmp(name,idp,line,type)
  1671.     char *name;    /* User's login id */
  1672.     char *idp;    /* 4-byte line id for utmp entry */
  1673.     char *line;    /* Device (port) name */
  1674.     int   type;
  1675. {    char *p, *q;
  1676.     int   i;
  1677.  
  1678.     D6("fillutmp(%lX,%lX,%lX,%d)",name,idp,line,type);
  1679.     if (name) D5("fillutmp: name=\"%s\"",name);
  1680.     if ( idp) D5("fillutmp:  idp=\"%s\"", idp);
  1681.     if (line) D5("fillutmp: line=\"%s\"",line);
  1682.     if (up == 0) {        /* No ttyslot!!! */
  1683.         D5("utmp:before setutent()");
  1684.         setutent();            /* Make pututline rescan the file */
  1685.         up = &utmp;
  1686.     }
  1687. #ifdef SYS5
  1688.     D5("up=%06lX",up);
  1689.     D5("utmp: Copy name \"%s\"",up->ut_user);
  1690.     CP(up->ut_user,name,8);            /* Fill in the user field with the login id */
  1691.     D5("utmp: Copy   id \"%s\"",up->ut_id);
  1692.     CP(up->ut_id,  idp, 8);            /* The "id" field is from the /etc/inittab entry */
  1693.     D5("utmp: Copy line \"%s\"",up->ut_line);
  1694.     CP(up->ut_line,line,12);        /* Copy the device name to the line field */
  1695.     up->ut_pid  = getpid();            /* This is probably already correct, but... */
  1696.     up->ut_type = type;
  1697.     up->ut_exit.e_termination = 0;        /* Default exit codes are all zero */
  1698.     up->ut_exit.e_exit = 0;
  1699.     D5("utmp: Note time...");
  1700.     time(&currtime);
  1701.     up->ut_time = currtime;            /* Tell the OS when (s)he logged in */
  1702.     if (debug >= 5) Hexdnm(up,sizeof(struct utmp),"utmp");
  1703. #endif
  1704. /*
  1705. ** No return value; the caller trusts us to do it right.
  1706. */
  1707. }
  1708. \!Funky\!Stuff\!
  1709. echo file: findutmp.c
  1710. cat > findutmp.c << '\!Funky\!Stuff\!'
  1711. #include "uutty.h"
  1712. /* 
  1713. ** Try to find our entry in the /etc/utmp file.
  1714. ** If we find it, it is copied to our global utmp.
  1715. ** This works on SYS/V, and probably on SYS/III,
  1716. ** but likely not on anything else.
  1717. */
  1718. struct utmp *
  1719. findutmp()
  1720. {    int rec;        /* Record number, used in debug output */
  1721.  
  1722.     pid = getpid();        /* We are looking for an entry with out process id */
  1723.     rec = 0;        /* No records read so far */
  1724.     up  = 0;        /* No entry unpacked so far */
  1725. #ifdef SYS5
  1726.     setutent();        /* Restart at the top of the file */
  1727. loop:
  1728.     D5("before getutent()");
  1729.     errno = 0;
  1730.     up = getutent();    /* Read in one /etc/utmp entry */
  1731.     ++rec;
  1732.     D4("getutent()=%06lX rec=%d\t[errno=%d]",up,rec,errno);
  1733.     if (up == 0) {
  1734.         D3("findutmp() FAILED.");
  1735.         return 0;
  1736.     }
  1737.     if (debug >= 5) Hexdnm(up,sizeof(struct utmp),"utmp");
  1738.     if (up->ut_pid != pid) {
  1739.         D4("findutmp: rec=%d pid=%d wrong.",rec,pid);
  1740.         Loop;
  1741.     }
  1742.     D4("findutmp: rec=%d pid=%d is me.",rec,pid);
  1743.     copy(&utmp,up,sizeof(struct utmp));
  1744.     up = &utmp;
  1745.     return up;
  1746. #endif
  1747. }
  1748. \!Funky\!Stuff\!
  1749. echo file: gestate.c
  1750. cat > gestate.c << '\!Funky\!Stuff\!'
  1751. #include "uutty.h"
  1752. /* 
  1753. ** Look up the current state and return its symbolic name.
  1754. **
  1755. ** The state[] array is the list of known states.  Note that 
  1756. ** we assume that states are non-negative, and use -1 as an 
  1757. ** end-of-array flag.  Note also that zero is a highly-likely 
  1758. ** state, and should be included as a distinct state (probably 
  1759. ** S_INIT).  The order is irrelevant, except for speed; a linear 
  1760. ** lookup is done.
  1761. */
  1762. struct state {int ssval; char *ssnam; } state[] = {
  1763.     {S_EXIT,    "EXIT"},
  1764.     {S_IDLE,    "IDLE"},
  1765.     {S_INIT,    "INIT"},
  1766.     {S_LOGIN,    "LOGIN"},
  1767.     {S_PASSWD,    "PASSWD"},
  1768.     {-1,        "UNKNOWN"}
  1769. };
  1770. char *
  1771. gestate()
  1772. {    int i;
  1773.  
  1774.     for (i=0; state[i].ssval >= 0; i++)
  1775.         if (state[i].ssval == ss)
  1776.             return state[i].ssnam;
  1777.     return state[i].ssnam;            /* Final "unknown" state */
  1778. }
  1779. \!Funky\!Stuff\!
  1780. echo file: getime.c
  1781. cat > getime.c << '\!Funky\!Stuff\!'
  1782. #include "uutty.h"
  1783. /* 
  1784. ** Get the current local time, return pointer to the ASCII version.
  1785. */
  1786. char *getime()
  1787. {
  1788.         time(&currtime);        /* 32-bit UNIX timestamp */
  1789.         ctimep = ctime(&currtime);    /* Convert to ASCII */
  1790.         ctimep[24] = '\0';        /* We don't want the newline */
  1791.         return ctimep;
  1792. }
  1793. \!Funky\!Stuff\!
  1794. echo file: help.c
  1795. cat > help.c << '\!Funky\!Stuff\!'
  1796. #include "uutty.h"
  1797. /* 
  1798. ** The -h option triggers this routine.  We should try to
  1799. ** keep it up to date, so users can find out easily what
  1800. ** options are currently supported.
  1801. */
  1802. help()
  1803. {
  1804.     P("usage: %s [-options] [device] [2>auditfile]",progname);
  1805.     P("options are:");
  1806.     P("\t-b<n>\tSet baud rate to <n>.");
  1807.     P("\t-c<n>\tCount to <n> before reads.");
  1808.     P("\t-e<msg>\tMessage to send to port before exiting.");
  1809.     P("\t-f\tFork (create subprocess) to start shells.");
  1810.     P("\t-h\tHelp--display this information.");
  1811.     P("\t-i<msg>\tMessage to send for initalizing port.");
  1812.     P("\t-l\tCreate uucp lockfiles for successful logins.");
  1813.     P("\t-n<msg>\tMessage to send to nudge the port.");
  1814.     P("\t-p<f>\tPort name is <f>.");
  1815.     P("\t-r<n>\tRaw I/O [default=1=true].");
  1816.     P("\t-s<n>\tSleep <n> seconds before reads.");
  1817.     P("\t-x<n>\tDebug level of <n>.");
  1818.     P("Note that error output [file 2] is used for debugging.");
  1819. }
  1820. \!Funky\!Stuff\!
  1821.  
  1822.  
  1823.